#ifndef TOURNAMENT_H_
#define TOURNAMENT_H_

#include "chef.h"
#include "judge.h"
#include "list.h"

typedef struct tournament_t *Tournament;

typedef enum {
	TOURNAMENT_SUCCESS,
	TOURNAMENT_INVALID_ARGUMENT,
	TOURNAMENT_OUT_OF_MEMORY,
	TOURNAMENT_CHEF_ALREADY_EXISTS,
	TOURNAMENT_SAME_CHEF,
	TOURNAMENT_NO_JUDGES,
	TOURNAMENT_CHEF_HAS_NO_DISHES
} TournamentResult;

/**
 * Creates new Tournament
 * @param result a pointer to put error codes in. (ignore it if NULL)
 * result value:
 * TOURNAMENT_OUT_OF_MEMORY if memory allocation failed
 * TOURNAMENT_SUCCESS otherwise
 * @return
 * NULL if error occured
 * A new Tournament otherwise
 */
Tournament tournamentCreate(TournamentResult *result);

/**
 * Creates clone of existing Tournament
 * @param tournament The Tournament to copy
 * @param result a pointer to put error codes in. (ignore it if NULL)
 * result value:
 * TOURNAMENT_INVALID_ARGUMENT if tournament is NULL
 * TOURNAMENT_OUT_OF_MEMORY if memory allocation failed
 * TOURNAMENT_SUCCESS otherwise
 * @return
 * NULL if error occured
 * A new Tournament (clone of tournament) otherwise
 */
Tournament tournamentCopy(Tournament tournament, TournamentResult *result);

/**
 * Destroys Tournament
 * @param tournament The Tournament to destroy (does nothing if it's NULL)
 */
void tournamentDestroy(Tournament tournament);

/**
 * Reset Tournament to its inital state.
 * @param tournament The Tournament to reset (does nothing if it's NULL)
 */ 
void tournamentClear(Tournament tournament);

/**
 * Adds Chef to Tournament
 * @param tournament The Tournament to add the Chef to
 * @param chef The Chef to Add
 * @return
 * TOURNAMENT_INVALID_ARGUMENT if tournament or chef is NULL
 * TOURNAMENT_OUT_OF_MEMORY if memory allocation failed
 * TOURNAMENT_CHEF_ALREADY_EXISTS if tournament already contains Chef
 * 	whose name is exactly as chef's name
 * TOURNAMENT_SUCCESS otherwise
 */
TournamentResult tournamentAddChef(Tournament tournament, Chef chef);

/**
 * Adds Judge to Tournament
 * @param tournament The Tournament to add the Judge to
 * @param judge The Judge to Add
 * @return
 * TOURNAMENT_INVALID_ARGUMENT if tournament or judge is NULL
 * TOURNAMENT_OUT_OF_MEMORY if memory allocation failed
 * TOURNAMENT_SUCCESS otherwise
 */
TournamentResult tournamentAddJudge(Tournament tournament, Judge judge);

/**
 * Get Chef by name
 * @param tournament The Tournament to search Chef in
 * @param name The name of the wanted Chef
 * @return
 * NULL if tournament or name is NULL
 * NULL if tournament doesn't contain such named Chef
 * The Chef named name, if found.
 * Note: the actual chef is returned. not a copy of it.
 */
Chef tournamentGetChef(Tournament tournament, const char *name);

/**
 * Get the leading Chef
 * Get the Chef whose score is highest.
 * (If there are two or more, return the first
 * one, in lexicographical order of names)
 * @param tournament The Tournament to get its leading Chef
 * @return
 * NULL if tournament is NULL, or if it contains no Chefs.
 * The leading Chef, otherwise.
 * Note: the actual chef is returned. not a copy of it.
 */
Chef tournamentGetLeadingChef(Tournament tournament);

/**
 * Get the names of Judges
 * @param tournament The Tournament to get its Judges
 * @param names A List of string, to put the names in
 * @return
 * TOURNAMENT_INVALID_ARGUMENT if tournament or names is NULL
 * TOURNAMENT_OUT_OF_MEMORY if memory allocation failed
 * (In that case, names may contain some of the names)
 * TOURNAMENT_SUCCESS otherwise
 */
TournamentResult tournamentGetJudgesNames(Tournament tournament, List names);

/**
 * Compete between Chefs
 * @param tournament The Tournament to compete Chefs in
 * @param chef1 First Chef to compete
 * @param chef2 Second Chef to compete
 * @param resignJudgesNames List of string, to add the names of the
 * 	resigned Judges to (ignore it if NULL)
 * @param result a pointer to put error codes in. (ignore it if NULL)
 * result value:
 * TOURNAMENT_INVALID_ARGUMENT if tournament, chef1 or chef2 are NULL
 * TOURNAMENT_SAME_CHEF if chef1 and chef2 are the same Chef
 * TOURNAMENT_NO_JUDGES if there are no Judges to make a judge
 * TOURNAMENT_CHEF_HAS_NO_DISHES if at least one of the Chefs has no dishes
 * TOURNAMENT_OUT_OF_MEMORY if a memory allocation failed (in that case,
 * 	resignJudgeNames may contain partial data)
 * TOURNAMENT_SUCCESS otherwise
 * @return
 * positive number if chef1 won
 * negative number if chef2 won
 * 0 in case of tie or error
 */
int tournamentCompeteChefs(Tournament tournament, Chef chef1, Chef chef2,
		List resignJudgesNames, TournamentResult *result);

#endif /* TOURNAMENT_H_ */
